<?php
/*
Plugin Name: Simple Classified Ads
Plugin URI: http://localreport.org/
Description: Add a simple classified page to your site, with custom post types.
Version: 0.1
Author: Jeremy Rue
Author URI: http://localreport.org/
License: GPL2

Copyright 2011  JEREMY RUE  (email : jrue@localreport.org)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2, as 
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

class SimpleClassifieds{

	function SimpleClassifieds()
	{
		// Creates classified post type labels
		$classified_labels = array(
			'name' => _x('Classifieds', 'Classifieds custom post type general plural name'),
			'singular_name' => _x('Classified', 'Classifieds custom post type singular name'),
			'add_new' => _x('Add New', 'Classified'),
			'add_new_item' => __('Add New Classified'),
			'edit_item' => __('Edit Classified'),
			'new_item' => __('New Classified'),
			'view_item' => __('View Classified'),
			'search_items' => __('Search Classifieds'),
			'not_found' =>  __('No classified ads found'),
			'not_found_in_trash' => __('No classified ads found in Trash'), 
			'parent_item_colon' => '',
			'menu_name' => __('Classified Ads')
		);
		
		//Classifieds only use title, editor, thumbnail and author. 
		$classified_support = array(
			'title',
			'editor',
			'thumbnail',
			'author',
		);
		
		//put it all together
		$classified_label = array(
			'labels' => $classified_labels,
			'public' => true,
			'show_ui' => true,
			'capability_type' => 'post',
			'hierarchical' => false,
			'rewrite' => array('slug' => 'classifieds', 'with_front' => TRUE),
			'query_var' => true,
			'supports' => $classified_support
		);
		
		//register this custom post type in WP
		register_post_type('simple_classifieds', $classified_label);
		
		//Some JS and CSS for the date picker form only in the admin
		add_action('admin_print_scripts', array(&$this, 'add_classified_admin_scripts') );
		add_action('admin_print_styles', array(&$this, 'add_classified_admin_styles') );
	
		//Build the form box for classifieds custom posts, and save meta data
		add_action('admin_init', array(&$this, 'admin_init') );
		add_action('save_post', array(&$this, 'save_classified_data') );
		
		//messages after you submit the form
		add_filter('post_updated_messages', array(&$this, 'classifieds_updated_messages') );
		
		//add settings menu for Googles re-captcha code
		if ( is_admin() ){
			add_action('admin_menu', array(&$this, 'classifieds_menu_page') );
			add_action('admin_init', array(&$this, 'classifieds_settings') );
		}
	}
	
	function add_classified_admin_scripts()
	{
		//For the date picker to show up when clicking inside date field in admin
		$plugin_dir = WP_PLUGIN_URL.'/'.str_replace(basename( __FILE__), "", plugin_basename(__FILE__));
		wp_enqueue_script('jquery');
		wp_enqueue_script('jquery_date_picker', $plugin_dir .'js/jquery-ui-1.8.11.custom.min.js', array('jquery'), '1.2.1');
		wp_enqueue_script('jquery_classified', $plugin_dir .'js/date.form.js', array('jquery','jquery_date_picker'), '0.1');
	}
	
	function add_classified_admin_styles()
	{
		//date picker styles
		$plugin_dir = WP_PLUGIN_URL.'/'.str_replace(basename( __FILE__), "", plugin_basename(__FILE__));
		wp_enqueue_style('jquery_date_picker_css', $plugin_dir .'js/css/smoothness/jquery-ui-1.8.11.custom.css');
	}
	
	function admin_init() 
	{
		// Custom meta boxes for expiration, price and location
		add_meta_box('classifieds-meta', 'Classified Options', array(&$this, 'meta_options'), 'simple_classifieds', 'normal', 'high');
	}

	// Admin post meta contents
	function meta_options()
	{
		global $post;
		
		//security measure to make sure this form submission comes only from this page
		wp_nonce_field( plugin_basename( __FILE__ ), 'simpleclassified_noncename' );
		
		//pre-populate forms with saved data
		$custom = get_post_custom($post->ID);
		$classified_exp_date = $custom['_classified-expiration'][0] ?  $custom['_classified-expiration'][0] : date("m/d/y");
		$classified_price = $custom['_classified-price'][0] ?  $custom['_classified-price'][0] : '$0.00';
		$classified_location = $custom['_classified-location'][0] ?  $custom['_classified-location'][0] : 'Mission';
		$classified_contact = $custom['_classified-contact-email'][0] ? $custom['_classified-contact-email'][0] : get_option('admin_email');
		
		//HTML for meta forms for expiration, price and location
		_e("<p><label for=\"classified-expiration\">Expire this classified on:</label><br />\n");
		_e("<input name=\"classified-expiration\" id=\"classified-expiration\" class=\"classified-expiration\" type=\"text\" value=\"$classified_exp_date\"/></p>\n");
		_e("<p><label for=\"classified-price\">Price (include dollar sign):</label><br />\n");
		_e("<input name=\"classified-price\" id=\"classified-price\" type=\"text\" value=\"$classified_price\" /></p>\n");
		_e("<p><label for=\"classified-location\">Location (e.g. Mission District, East Bay, etc.):</label><br />\n");
		_e("<input name=\"classified-location\" id=\"classified-location\" type=\"text\" value=\"$classified_location\" /></p>\n");
		_e("<p><label for=\"classified-contact-email\">E-mail address of classified poster (won't be displayed on posting):</label><br />\n");
		_e("<input name=\"classified-contact-email\" id=\"classified-contact-email\" type=\"text\" value=\"$classified_contact\" /></p>\n");
	}

	function save_classified_data($post_id) 
	{	
		// verify this came from the our screen and with proper authorization.
		if ( !wp_verify_nonce( $_POST['simpleclassified_noncename'], plugin_basename( __FILE__ ) ))
			return $post_id;

		// verify if this is an auto save routine. If it is, our form has not been submitted, so we dont want to do anything
		if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
			return $post_id;

		// Check permissions
		if ( !current_user_can( 'publish_pages', $post_id ) )
			return $post_id;

		// OK, we're authenticated: we need to find and save the data	
		$post = get_post($post_id);
		if ($post->post_type == 'simple_classifieds') { 
			update_post_meta($post_id, '_classified-expiration', esc_attr($_POST['classified-expiration']) );
			update_post_meta($post_id, '_classified-price', esc_attr($_POST['classified-price']) );
			update_post_meta($post_id, '_classified-location', esc_attr($_POST['classified-location']) );
			update_post_meta($post_id, '_classified-contact-email', esc_attr($_POST['classified-contact-email']) );
		}
		return $post_id;
	}
	
	function classifieds_menu_page()
	{
		add_options_page(__('Settings for classifieds plugin'), __('Classifieds settings'), 'activate_plugins', 'classifieds_menu', array(&$this, 'classifieds_submenu_for_captcha'));
	}
	
	function classifieds_settings()
	{
		register_setting( 'classifieds-settings-group', 'recaptcha-code-for-classifieds', array(&$this, 'classifieds_settings_validate') );
		add_settings_section('classifieds-recaptcha', __('Recaptcha code so public can submit inquires'), array(&$this, 'recaptcha_form_text'), 'classifieds-settings-group');
		add_settings_field('classifieds_public_input_id', __('PUBLIC API KEY:'), array(&$this, 'recaptcha_public_api_form_input'), 'classifieds-settings-group', 'classifieds-recaptcha');
		add_settings_field('classifieds_private_input_id', __('PRIVATE API KEY:'), array(&$this, 'recaptcha_private_api_form_input'), 'classifieds-settings-group', 'classifieds-recaptcha');
	}
	
	function recaptcha_public_api_form_input()
	{
		$options = get_option('recaptcha-code-for-classifieds');
		printf(__("<p><input id='classified-public-api' name='recaptcha-code-for-classifieds[public_key]' size='60' type='text' value='%s' /></p>"), $options['public_key']);
	}
	
	function recaptcha_private_api_form_input()
	{
		$options = get_option('recaptcha-code-for-classifieds');
		printf(__("<p><input id='classified-private-api' name='recaptcha-code-for-classifieds[private_key]' size='60' type='text' value='%s' /></p>"), $options['private_key']);
	}
	
	
	function recaptcha_form_text()
	{
		_e('<p>This Classifieds plugin uses <a href="http://www.google.com/recaptcha/">Google\'s re-captcha</a> as a security feature for allowing the general public to contact sellers.</p>');
		printf(__('<p>Re-captcha is free, but it does require you to <a href="https://www.google.com/recaptcha/admin/create?domains=%s&app=simple-classifieds-wordpress-plugin">register</a> your domain on their site.</p>'), $_SERVER['HTTP_HOST']);
		_e('<p><em>Please note: Registering with re-captcha is optional, but the public won\'t be able to contact sellers without it.</em></p>');
	}
	
	function classifieds_settings_validate($inputs)
	{
		//recaptcha api keys need to be exactly 40 characters with no spaces
		$output = array();
		foreach($inputs as $key=>$input){
			$input = trim($input);
			$input = preg_replace('/\s*/m', '', $input);
			$output[$key] = substr($input, 0, 40);
		}
		return $output;
	}
	
	function classifieds_submenu_for_captcha()
	{
		if (!current_user_can('activate_plugins'))  {
			wp_die( __('You do not have sufficient permissions to access this page.') );
		}
		echo '<div class="wrap">';
		echo '<form method="post" action="options.php">';
		settings_fields( 'classifieds-settings-group' ); 
	    do_settings_sections( 'classifieds-settings-group' );
		?>
		<p class="submit">
			<input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
		</p>
		</form>
		</div>
		<?php
	}
	

	
	function classifieds_updated_messages( $messages ) 
	{
		global $post, $post_ID;
		$messages['simple_classifieds'] = array(
			0 => '', // Unused. Messages start at index 1.
			1 => sprintf( __('Classified updated. <a href="%s">View classified</a>'), esc_url( get_permalink($post_ID) ) ),
			2 => __('Custom field updated.'),
			3 => __('Custom field deleted.'),
			4 => __('Classified updated.'),
			/* translators: %s: date and time of the revision */
			5 => isset($_GET['revision']) ? sprintf( __('Classified restored to revision from %s'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
			6 => sprintf( __('Classified published. <a href="%s">View classified</a>'), esc_url( get_permalink($post_ID) ) ),
			7 => __('Classified saved.'),
			8 => sprintf( __('Classified submitted. <a target="_blank" href="%s">Preview classified</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
			9 => sprintf( __('Classified scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview classified</a>'),
			// translators: Publish box date format, see http://php.net/date
			date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
			10 => sprintf( __('Classified draft updated. <a target="_blank" href="%s">Preview classified</a>'), esc_url( add_query_arg( 'preview', 'true', get_permalink($post_ID) ) ) ),
		);
		return $messages;
	}
	
}

function classified_mail_form()
{	
	$classified_keys = get_option('recaptcha-code-for-classifieds');
	if(!$classified_keys || strlen($classified_keys['public_key']) != 40 || strlen($classified_keys['private_key']) != 40){
		return;
	}

	$custom = get_post_custom($post->ID);
	$admin_email = get_option('admin_email');
	
	//adding captcha technology
	require_once('recaptchalib.php');
	$captcha_publickey =  $classified_keys['public_key']; 
	$captcha_privatekey = $classified_keys['private_key']; 
	# the response from reCAPTCHA
	$captcha_resp = null;
	# the error code from reCAPTCHA, if any
	$captcha_error = null;
	// if send is set but fake e-mail is not...
	// spam robots often fill in all form fields, so if the hidden e-mail 
	// has a value...it's probably spam.
	if(!empty($_POST['send_mail']) && empty($_POST['e-mail']))
	{
		$captcha_resp = recaptcha_check_answer ($captcha_privatekey, $_SERVER["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]);

        if ($captcha_resp->is_valid) {
			if (!classified_email_check($_POST["classified_email"])){
				_e('<span style="color:red"><strong>Sorry, this is not a valid e-mail, please enter a valid email address.</strong></span>');
			} else {
				$to = $custom['_classified-contact-email'][0] && $custom['_classified-contact-email'][0] != $admin_email ? $custom['_classified-contact-email'][0] : $admin_email;
				$subject = sprintf(__("Inquiry regarding your classified on %s"), $_SERVER['HTTP_HOST']);

				$message = sprintf(__("Someone has submitted a question regarding your classified on %s:\n\n"), $_SERVER['HTTP_HOST']);
				$message .= sprintf(__("From: %s\n"), stripslashes($_POST["classified_name"]));
				$message .= sprintf(__("Email: %s\n"), $_POST["classified_email"]);
				$message .= sprintf(__("Message: %s\n\n"), stripslashes($_POST["classified_message"]));
				$message .= sprintf(__("Sender's IP Address: %s\n\n"), $_SERVER["REMOTE_ADDR"]);
				$message .= __("(A copy of this message has been sent to the site admin.)");

				$from = $_POST["classified_email"];
		
				$headers = 'From: "'. stripslashes($_POST["classified_name"]) .'" <' . $from . ">\r\n" . 
						'Bcc: ' . $admin_email . "\r\n" .
						'Reply-To: "' . stripslashes($_POST["classified_name"]) . '" <' . $from  . ">\r\n" . 
						'X-Mailer: PHP/' . phpversion();

				if(mail($to,$subject,$message,$headers))
				{
					$sent = true;
				}else{
					$sent = false;
				}
			}
		} else {
			$captcha_error = $captcha_resp->error;
			if($captcha_error == "invalid-site-private-key"){
				_e('<span style="color:red"><strong>Sorry, this site is using an incorrect API key. Please try again later.</strong></span>');
			} else if($captcha_error == "incorrect-captcha-sol"){
				_e('<span style="color:red"><strong>Sorry, there was an error entering the verification words. Please try again.</strong></span>');
			} else {
				_e('<span style="color:red"><strong>Sorry, there was a problem verifying the words.</strong></span>');
			}
			
		}

	}
	if($sent == true) { ?>
		<h2><?php _e('Thank You!'); ?></h2>
		<p><strong><?php _e('Your message has been sent.'); ?></strong></p>
	<?php }else{ ?>
		<h2><?php _e('Submit question to this seller'); ?></h2>
	<?php } ?>
	<script type="text/javascript">
		var RecaptchaOptions = {
			theme : 'white'
		};
	</script>
	<p id="classified_message" class="hidden"></p>
	<div id="classified_contact_form">
		<form method="post" target="_self" action="" onsubmit="javascript:return validate_classified_form(this);">
			<div class="classified_field"><label for="classified_name"><?php _e('Your Name'); ?></label><br /><input type="text" name="classified_name" id="classified_name" class="classified_textbox" /></div>
			<div class="classified_field"><label for="classified_email"><?php _e('Your Email'); ?></label><br /><input type="text" name="classified_email" id="classified_email" class="classified_textbox" /></div>
			<div class="classified_field"><label for="classified_message"><?php _e('Message'); ?></label><br /><textarea cols="5" rows="5" name="classified_message" id="classified_message" class="classified_textbox" tabindex="4"><?php _e('Enter your message...'); ?></textarea></div>
			<div class="classified_field"><label><?php _e('(Spam prevention) Type in the two verification words:'); ?></label><br /><?php echo recaptcha_get_html($captcha_publickey, $captcha_error); ?></div>
			<div class="classified_field"><input type="submit" value="<?php _e('SUBMIT INQUIRY TO SELLER'); ?>" class="classified_submit" name="send_mail" class="button" /></div>
			<input type="hidden" name="e-mail" />
		</form>
	</div>
<?php
}

function classified_email_check($email)
{
   $isValid = true;
   $atIndex = strrpos($email, "@");
   if (is_bool($atIndex) && !$atIndex)
   {
      $isValid = false;
   }
   else
   {
      $domain = substr($email, $atIndex+1);
      $local = substr($email, 0, $atIndex);
      $localLen = strlen($local);
      $domainLen = strlen($domain);
      if ($localLen < 1 || $localLen > 64)
      {
         // local part length exceeded
         $isValid = false;
      }
      else if ($domainLen < 1 || $domainLen > 255)
      {
         // domain part length exceeded
         $isValid = false;
      }
      else if ($local[0] == '.' || $local[$localLen-1] == '.')
      {
         // local part starts or ends with '.'
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $local))
      {
         // local part has two consecutive dots
         $isValid = false;
      }
      else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain))
      {
         // character not valid in domain part
         $isValid = false;
      }
      else if (preg_match('/\\.\\./', $domain))
      {
         // domain part has two consecutive dots
         $isValid = false;
      }
      else if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local)))
      {
         // character not valid in local part unless 
         // local part is quoted
         if (!preg_match('/^"(\\\\"|[^"])+"$/',
             str_replace("\\\\","",$local)))
         {
            $isValid = false;
         }
      }
      if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A")))
      {
         // domain not found in DNS
         $isValid = false;
      }
   }
   return $isValid;
}

add_action('init', 'SimpleClassifiedInit');

function SimpleClassifiedInit(){ 
	global $simpleClassified; 
	$simpleClassified = new SimpleClassifieds();
}

function classifieds_rewrite_flush() {
  SimpleClassifiedInit();
  flush_rewrite_rules();
}
register_activation_hook(__FILE__, 'classifieds_rewrite_flush');
?>